/*
Copyright © 2024 NAME HERE <EMAIL ADDRESS>
*/
package cmd

import (
	"fmt"
	"github.com/fatih/color"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"gorm.io/gorm"
	"nodemessage.com/codetool/config"
	"nodemessage.com/codetool/logic"
	"nodemessage.com/codetool/model"
	"nodemessage.com/codetool/util/strutil"
	"path"
	"strings"
)

var (
	// gencode 配置
	confGenCode *viper.Viper
	connectDb   *gorm.DB
	conf        = model.ConfGenCode{}
	projectName string
)

// gencodeCmd represents the gencode command
var gencodeCmd = &cobra.Command{
	Use:   "gencode",
	Short: "代码生成",
	Long:  `JavaBase代码生成.`,
	PreRun: func(cmd *cobra.Command, args []string) {
		confGenCode = config.ConfGenCode(projectName)
		err := confGenCode.Unmarshal(&conf)
		if err != nil {
			panic(err)
		}
		connectDb = config.ConnectDb(conf)
		showConfig()
	},
	Run: func(cmd *cobra.Command, args []string) {
		genFlag, genTable := showTables()
		if !genFlag {
			// 不生成项目代码
			return
		} else {
			// 生成项目代码
			if projectName != "" {
				conf.JavaMeta.BasePath = path.Join(projectName, conf.JavaMeta.BasePath)
			}
			genTables(genTable)
		}
	},
}

func showConfig() {
	fmt.Println("\n====  当前配置信息  ====")
	fmt.Println("\n> 作者: " + strutil.ColorValueStr(conf.JavaMeta.Author))
	fmt.Println("> 包名: " + strutil.ColorValueStr(conf.JavaMeta.BasePackage))
	printGenFile("实体类", conf.JavaMeta.Entity)
	printGenFile("Dao类", conf.JavaMeta.Dao)
	printGenFile("Service类", conf.JavaMeta.Service)
	printGenFile("Service实现类", logic.MetaGen{
		Gen:       conf.JavaMeta.ServiceImpl.Gen,
		Overwrite: conf.JavaMeta.ServiceImpl.Overwrite,
		Package:   conf.JavaMeta.Service.Package + ".impl",
		Suffix:    conf.JavaMeta.Service.Suffix + "Impl",
	})
	printGenFile("Controller类", conf.JavaMeta.Controller)
	fmt.Println()
	fmt.Println("\n> 数据库Ip地址: " + strutil.ColorValueStr(conf.Db.Host))
	fmt.Println("> 数据库端口: ", strutil.ColorValueFormatStr("%d", conf.Db.Port))
	fmt.Println("> 数据库用户名: " + strutil.ColorValueStr(conf.Db.UserName))
	fmt.Println("> 数据库密码: " + strutil.ColorValueStr(conf.Db.Password))
	fmt.Println("> 数据库名: " + strutil.ColorValueStr(conf.Db.DataBase))
	fmt.Println("\n====  " + color.HiRedString(config.ConfigFile) + "  ====\n")
}

func showTables() (genFlag bool, genTable []model.DbTable) {
	table, err := model.DbInfo{}.QueryTable(connectDb, conf.Db.DataBase)
	if err != nil {
		panic(err)
	}
	for _, t := range table {
		if !conf.ExistTable(t.Name) {
			continue
		}
		genTable = append(genTable, t)
	}
	fmt.Println("> 本次操作表:")
	for _, s := range genTable {
		fmt.Println(strutil.ColorValueStr("    * ") + s.Name + " (" + s.Comment + ")")
	}
	fmt.Printf("\n> 继续生成?(Y/N)> ")
	genFlagStr := ""
	_, _ = fmt.Scanf("%s", &genFlagStr)
	genFlag = strings.ToLower(genFlagStr) == "y"
	fmt.Println()
	return
}

func genTables(genTable []model.DbTable) {
	for _, t := range genTable {
		camelCaseName := strutil.SnakeToCamelCase(t.Name)
		javaBuilder := logic.BuilderJavaGen(conf.JavaMeta).
			BuildJavaDao(logic.JavaDao{
				JavaBase: logic.JavaBase{
					Package: conf.JavaMeta.Dao.Package,
					Name:    camelCaseName,
					Suffix:  conf.JavaMeta.Dao.Suffix,
					Comment: "dao类 " + t.Comment,
				},
			}).
			BuildJavaService(logic.JavaService{
				JavaBase: logic.JavaBase{
					Package: conf.JavaMeta.Service.Package,
					Name:    camelCaseName,
					Suffix:  conf.JavaMeta.Service.Suffix,
					Comment: "service类",
				},
			}).
			BuildJavaController(logic.JavaController{
				JavaBase: logic.JavaBase{
					Package: conf.JavaMeta.Controller.Package,
					Name:    camelCaseName,
					Suffix:  conf.JavaMeta.Controller.Suffix,
					Comment: "controller类",
				},
				ModelUrl: "/" + strutil.FirstToLower(camelCaseName),
			})
		fields, err := t.QueryField(connectDb)
		if err != nil {
			panic(err)
		}
		var javaField []logic.JavaField
		for _, f := range fields {
			javaField = append(javaField, logic.JavaField{
				Name:    strutil.FirstToLower(strutil.SnakeToCamelCase(f.Name)),
				Type:    logic.DaoTypeToType(f.ColumnType),
				Comment: f.Comment,
			})
		}

		javaBuilder.BuildJavaEntity(logic.JavaEntity{
			JavaBase: logic.JavaBase{
				Package: conf.JavaMeta.Entity.Package,
				Name:    camelCaseName,
				Suffix:  conf.JavaMeta.Entity.Suffix,
				Comment: "实体类 " + t.Comment,
			},
			TableName: t.Name,
			Field:     javaField,
		})
		build := javaBuilder.Build()
		if build.JavaMeta.Entity.Gen {
			err = build.GenEntity(build.JavaMeta.Entity.Overwrite)
			if err != nil {
				panic(err)
			}
		}
		if build.JavaMeta.Dao.Gen {
			err = build.GenDao(build.JavaMeta.Dao.Overwrite)
			if err != nil {
				panic(err)
			}
		}
		if build.JavaMeta.Service.Gen {
			err = build.GenService(build.JavaMeta.Service.Overwrite)
			if err != nil {
				panic(err)
			}
		}
		if build.JavaMeta.ServiceImpl.Gen {
			err = build.GenServiceImpl(build.JavaMeta.ServiceImpl.Overwrite)
			if err != nil {
				panic(err)
			}
		}
		if build.JavaMeta.Controller.Gen {
			err = build.GenController(build.JavaMeta.Controller.Overwrite)
			if err != nil {
				panic(err)
			}
		}
	}
}

func printGenFile(desc string, metaGen logic.MetaGen) {
	cursor := ">"
	overwrite := ""
	if metaGen.Overwrite {
		overwrite = "是"
	} else {
		overwrite = "否"
	}
	yes := color.New(color.FgHiBlue, color.BgHiWhite, color.Bold).Sprintf("Y")
	if metaGen.Gen {
		fmt.Printf("\n%s [%s] %s | Package: %s | 类后缀: %s | 是否覆盖生成: %s", cursor, yes,
			strutil.ColorLabelStr(desc),
			strutil.ColorLabelStr(conf.JavaMeta.BasePackage+"."+metaGen.Package),
			strutil.ColorLabelStr("Xxx"+metaGen.Suffix),
			strutil.ColorValueStr(overwrite),
		)
	} else {
		fmt.Printf("\n%s [%s] %s | Package: %s | 类后缀: %s | 是否覆盖生成: %s", cursor, " ",
			strutil.ColorLabelStr(desc),
			strutil.ColorLabelStr(conf.JavaMeta.BasePackage+"."+metaGen.Package),
			strutil.ColorLabelStr("Xxx"+metaGen.Suffix),
			strutil.ColorValueStr(overwrite),
		)
	}
}

func init() {
	rootCmd.AddCommand(gencodeCmd)
	gencodeCmd.Flags().StringVarP(&projectName, "pro", "p", "", "maven项目名称,将用于文件夹命名与pom项目命名.")
}
